/************************************************************************

								Heroes IV
					  Copyright 2001, The 3DO Company

	------------------------------------------------------------------
  						 combat_ai_ranged_single_action.cpp

	$Header: $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "combat_ai_ranged_single_action.h"

#include <sstream>
#include "battlefield.h"
#include "combat_ai.h"
#include "combat_creature.h"
#include "debug_message.h"
#include "difficulty_level.h"
#include "random.h"

void t_combat_ai_ranged_single_action::weigh_action(t_combat_ai const& owner)
{	
	if (has_been_weighed())
		return;

	t_battlefield &battlefield = m_battlefield;

	t_combat_creature const& attacker = owner.get_actor();

	// Determine retaliation effects 
	int damage, retal_damage;
	t_combat_creature *retal_target = 0;

	int		attacks = attacker.get_attacks( true );
	double	weight;

	retal_damage = 0;
	damage = attacker.project_ranged_damage( *m_target, retal_damage, retal_target );
	weight = get_attack_weight(attacker, *m_target, damage);
	if (retal_damage > 0)
	{
		double retaliation_weight;
		double reduction;
		t_ai_combat_data_cache& data = battlefield.get_data_cache();

		retaliation_weight = retal_target->get_ai_value( retal_damage );
		reduction = data.get_retaliation_weight_reduction( *m_target, true );
		if (reduction > retaliation_weight)
			retaliation_weight = 0.0;
		else
			retaliation_weight -= reduction;
		weight -= retaliation_weight;
	}

	// A little touch of randomness..
	set_weight( weight );
}

double t_combat_ai_ranged_single_action::get_attack_weight(	t_combat_creature const& attacker,
															t_combat_creature const& target,
															int damage)
{
	if (damage == 0)
		return 0.0;

	t_battlefield &battlefield = attacker.get_battlefield();

	double weight = target.get_ai_value( damage );

	weight += t_combat_ai::get_zoc_change_weight(damage, target, false, 0);

	return weight;
}

// determine if we should wait on an attack
static bool should_wait( t_combat_creature const& attacker, t_combat_creature const& defender )
{
	// is the target a ranged attacker?
	t_battlefield& battlefield = attacker.get_battlefield();

	if (battlefield.get_difficulty() < k_difficulty_hard)
		return false;

	if (attacker.is_waiting())
		return false;

	if (!defender.is_awake())
		return true;

	// are we doing full damage to the target?
	if (battlefield.get_range_factor( attacker, defender ) == 1)
		return false;

	return !threatens_enemies( defender );
}

void t_combat_ai_ranged_single_action::perform_action(void)
{
	t_battlefield& battlefield = m_battlefield;

	if (should_wait( *battlefield.get_acting_creature(), *m_target ))
	{
		battlefield.wait_action();
		return;
	}
	battlefield.begin_ranged_attack( m_target );
}

